package model.impl;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import DAO.HibernateUtil;
import DAO.ScheduleDAO;
import DAO.StationDAO;
import DAO.impl.ScheduleDAOImpl;
import DAO.impl.StationDAOImpl;
import DTO.DTOManager;
import DTO.PassengerDTO;
import DTO.ScheduleDTO;

/**
 * Class that implements the model.Schedule interface.
 */
public class ScheduleImpl  implements model.Schedule {
	
	private ScheduleDAO scheduleDAO = new ScheduleDAOImpl();
	
	private Logger logger = LoggerFactory.getLogger("ScheduleImpl");
	
	private DTOManager dtoManager = new DTOManager();
	
	/**
	 * This method checks if there is a schedule in DB which has the same 
	 * DTO implementation as the given DTO. If it is NOT found in DB, method 
	 * creates a new Schedule entity from DTO and saves it.
	 * 
	 * @param scheduleDTO - DTO of schedule which is required to be saved
	 */
	public void saveUniqueSchedule(ScheduleDTO scheduleDTO) {
		try {
			HibernateUtil.beginTransaction();
			List<Schedule> foundSchedules = this.scheduleDAO
					.findIsSchedulePossible(scheduleDTO);
			if (foundSchedules == null || foundSchedules.isEmpty()) {
				Schedule schedule = this.dtoManager
						.createNewScheduleFromDTO(scheduleDTO);
				this.scheduleDAO.save(schedule);
			}
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in save unique schedule "
										+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		
	}
	
	/**
	 * This method checks if there is a schedule in DB which has the same 
	 * DTO implementation as given DTO. If it is found in DB, method 
	 * removes it.
	 * 
	 * @param scheduleDTO - DTO of schedule which is required to be removed
	
	 */
	public void removeUniqueSchedule(ScheduleDTO scheduleDTO) {
		try {
			HibernateUtil.beginTransaction();
			Schedule schedule = this.scheduleDAO
					.findScheduleByScheduleDTO(scheduleDTO);
			if (schedule != null) {
				this.scheduleDAO.delete(schedule);
			}
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in remove unique schedule " 
										+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
	}
	
	/**
	 * Checks given station and looks for all schedules that has this station 
	 * as arrival one.
	 * 
	 * @param  station - Station entity for which to look for Schedule
	 * @return         - List of Schedules which has the given station as an
	 * 					 instance variable or null if nothing was found
	 */
	public List<ScheduleDTO> getStationArrivalSchedule(Station station) {
		List<ScheduleDTO> arrivalSchedules = null;
		try {
			HibernateUtil.beginTransaction();
			ScheduleDTO temp = null;
			List<Schedule> schedules = this.scheduleDAO.findAll(Schedule.class);
			if (schedules != null) {
				for (int i = 0; i < schedules.size(); i++) {
					if (schedules.get(i).getStation1().getStationName()
							.equals(station.getStationName())) {
						if (arrivalSchedules == null) {
							arrivalSchedules = new ArrayList<ScheduleDTO>();
						}
						temp = new ScheduleDTO();
						temp.setDateOfDeparture(schedules.get(i)
								.getDateOfDeparture());
						temp.setDateOfArrival(schedules.get(i)
								.getDateOfArrival());
						temp.setStation1(station.getStationName());
						temp.setStation2(schedules.get(i).getStation2()
								.getStationName());
						temp.setTrainNumber(schedules.get(i).getTrain()
								.getTrainNumber());
						arrivalSchedules.add(temp);
					}
				}
			}
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in get station arrival schedule "
													+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		return arrivalSchedules;
	}

	/**
	 * Checks given station and looks for all schedules that has this station as
	 * departure one.
	 * 
	 * @param  station - Station entity for which to look for Schedule
	 * @return         - List of Schedules which has the given station as an 
	 * 					 instance variable or null if nothing was found
	 */
	public List<ScheduleDTO> getStationDeparturelSchedule(Station station) {
		List<ScheduleDTO> departurelSchedules = null;
		try {
			HibernateUtil.beginTransaction();
			ScheduleDTO temp = null;
			List<Schedule> schedules = this.scheduleDAO.findAll(Schedule.class);
			if (schedules != null) {
				for (int i = 0; i < schedules.size(); i++) {
					if (schedules.get(i).getStation2().getStationName()
							.equals(station.getStationName())) {
						if (departurelSchedules == null) {
							departurelSchedules = new ArrayList<ScheduleDTO>();
						}
						temp = new ScheduleDTO();
						temp.setDateOfDeparture(schedules.get(i)
								.getDateOfDeparture());
						temp.setDateOfArrival(schedules.get(i)
								.getDateOfArrival());
						temp.setStation2(station.getStationName());
						temp.setStation1(schedules.get(i).getStation1()
								.getStationName());
						temp.setTrainNumber(schedules.get(i).getTrain()
								.getTrainNumber());
						departurelSchedules.add(temp);
					}
				}
			}
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in get station departure schedule " 
													+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		return departurelSchedules;
	}


	/**
	 * Checks given DTO and fined the schedule that has the same DTO. If it's 
	 * found it looks for all passengers that has tickets for this schedule.
	 * 
	 * @param  scheduleDTO - DTO of schedule for which is required to find all 
	 * 						 passengers
	 * @return         	   - List of Passengers which has a ticket for this schedule 
	 *						 or null in any other cases.
	 */
	@Override
	public List<PassengerDTO> getAllPassengersOnSchedule(ScheduleDTO scheduleDTO) {
		List<PassengerDTO> passengers = null;
		try {
			HibernateUtil.beginTransaction();
			Schedule schedule = this.scheduleDAO
					.findScheduleByScheduleDTO(scheduleDTO);
			for(Ticket ticket : schedule.getTickets()) {
				if (passengers == null) {
					passengers = new ArrayList<PassengerDTO>();
				}
				passengers.add(this.dtoManager.createPassengerDTO(ticket
						.getPassenger()));
			}
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in get all passengers on schedule "
														+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		return passengers;
	}

	/**
	 * Method looks for all the Schedule entities in DB.
	 * 
	 * @return	- List of all Schedule entities in DB or null if there is no
	 * 			  schedules in DB.
	 */
	@Override
	public List<model.impl.Schedule> findAll() {
		List<model.impl.Schedule> schedules = null;
		try {
			HibernateUtil.beginTransaction();
			schedules = this.scheduleDAO.findAll(model.impl.Schedule.class);
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in find all schedules " 
													+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		return schedules;
	}

	/**
	 * Looks for all schedules that satisfy the given in scheduleDTO parameters.
	 * It is as is a wrapper with transaction for method findRequiredTrains in 
	 * {@link ScheduleDAO}.
	 * 
	 * @param scheduleDTO  - DTO of schedule for which is required to find trains.
	 * @return			   - List of ScheduleDTO which satisfy given parameters
	 * 					     or null if such Schedules was not found
	 */
	@Override
	public List<ScheduleDTO> findRequiredTrains(ScheduleDTO scheduleDTO) {
		List<ScheduleDTO> schedules = null;
		StationDAO stationDAO = new StationDAOImpl();
		try {
			HibernateUtil.beginTransaction();
			schedules = this.scheduleDAO.findRequiredTrains
				   (stationDAO.findStationByName(scheduleDTO.getStation1()),
					stationDAO.findStationByName(scheduleDTO.getStation2()), 
					scheduleDTO.getDateOfDeparture(), 
					scheduleDTO.getDateOfArrival());
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in find required trains "
													+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		return schedules;
	}	
}
